#include "ProductionBurnUid.h"
#include "InSdkDevInfo.h"

#define DEF_TAG         "BurnUid"

pStBurnUidReq g_pSt_BurnUid_Req = NULL;

void BurnUid_Set_ReuseAddr(int sockfd, int on)
{
    setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on);
}

int BurnUid_ConnectSever(int port)
{
    int sockfd;
    struct timeval timeout = {2, 0};
    struct sockaddr_in serv_addr;
    if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        perror("socket failed !!");
        return -1;
    }

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(port);
    serv_addr.sin_addr.s_addr = inet_addr(DEF_BURN_UID_IP);// htonl(INADDR_ANY);
    PRT_INFO(DEF_TAG,"burn uid server:%s port:%d\n", DEF_BURN_UID_IP, port);

    if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(struct timeval)) < 0)
    {
        PRT_ERR(DEF_TAG,"setsockopt: SO_SNDTIMEO error ....");
    }

    bzero(&(serv_addr.sin_zero), 8);
    if (connect(sockfd,(struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1)
    {
        close(sockfd);
        perror("connect error !");
        return -1;
    }
    else
    {
        BurnUid_Set_ReuseAddr(sockfd, 1);
        return sockfd;
    }
}

void BurnUid_Fill_HeadInfo(pStBurnUidHeader header_info, int cmd, int len)
{
    memset(header_info, 0, sizeof(StBurnUidHeader) );
    header_info->command_type = cmd;
    header_info->protocol_flag[0]='J';
    header_info->protocol_flag[1]='T';
    header_info->protocol_flag[2]='C';
    header_info->protocol_flag[3]='P';
    header_info->data_size = len;
}

int BurnUid_Check_HeadInfo(pStBurnUidHeader header_info, int cmd, int data_size)
{
    if ((header_info->command_type == cmd) &&
        (header_info->data_size == data_size) &&
        (header_info->protocol_flag[0] == 'J') &&
        (header_info->protocol_flag[1] == 'T') &&
        (header_info->protocol_flag[2] == 'C') &&
        (header_info->protocol_flag[3] == 'P'))
    {
        return 0;
    }
    return -1;
}

int BurnUid_Check_BurnStatus(int *server_fd,pStBurnUidHeader header_info, pStBurnUidResp resp)
{
    //再次读出对比是否写入配置文件正确
    int ret;
    int size;
    int sockfd = *server_fd;
    char uid[24] = {0};
    char authkey[36] = {0};
    StBurnUidResultReq result_req;

    memset(uid,0,sizeof(uid));
    memset(authkey,0,sizeof(authkey));
    memset(&result_req, 0, sizeof(result_req));
    memset(header_info, 0, sizeof(StBurnUidHeader));
    BurnUid_Fill_HeadInfo(header_info, COMMAND_TYPES_AUTO_BURN_UID_RESULT_REQ,sizeof(result_req));

    /* get device UUID */
    ret = Ext_InSdkGetInfo_UUID(uid);
    if(ret == DEF_COM_SUCCESS)
    {
        strcpy(result_req.device_id,uid);
    }

    /*get device AUTHKEY */
    ret = Ext_InSdkGetInfo_Authkey(authkey);
    if(ret == DEF_COM_SUCCESS)
    {
        strcpy(result_req.DeviceSecret,authkey);
    }

    //发送回复协议头及数据
    if ((strcmp(result_req.device_id, resp->device_id) == 0) &&
        (strcmp(result_req.DeviceSecret, resp->DeviceSecret) == 0) &&
        (strcmp(result_req.encrypt_mac, resp->encrypt_mac) == 0))
    {
        size = write(sockfd, header_info, sizeof(StBurnUidHeader));
        if(size >= sizeof(StBurnUidHeader))
        {
            size = write(sockfd,&result_req,sizeof(result_req));
            if(size >= sizeof(result_req))
            {
                StBurnUidResultResp resp_info;
                memset(header_info,0,sizeof(StBurnUidHeader) );
                int ret = read(sockfd, header_info, sizeof(StBurnUidHeader));
                if ((ret >= sizeof(StBurnUidHeader)) &&
                    (BurnUid_Check_HeadInfo(header_info, COMMAND_TYPES_AUTO_BURN_UID_RESULT_RESP,
                                            sizeof(resp_info)) == 0))
                {
                    memset(&resp_info, 0, sizeof(resp_info));

                    ret = read(sockfd, &resp_info, sizeof(resp_info));
                    if((ret >= sizeof(resp_info)))
                    {
                        PRT_INFO(DEF_TAG, "result: %d autoup: %d adder: %s\n", resp_info.result,
                                 resp_info.auto_upgrade, resp_info.upgrade_addr);
                        if((resp_info.result == 0) || (resp_info.result == 3))//烧写成功
                        {
                            close(sockfd);
                            *server_fd = -1;
                        }
                        return resp_info.result;
                    }
                }
            }
        }
    }
    return -1;
}

int BurnUid_From_Server(void)
{
    int ret, size;
    int sockfd;
    StBurnUidHeader header_info;

    while(1)
    {
        if ((sockfd = BurnUid_ConnectSever(DEF_BURN_UID_PORT)) > 0)
        {
			BurnUid_Fill_HeadInfo(&header_info, COMMAND_TYPES_AUTO_BURN_UID_REQ,
								  sizeof(StBurnUidReq));

			//发送协议头
            size = write(sockfd, &header_info, sizeof(header_info));
            if(size >= sizeof(header_info))
            {
                //发送测试结果数据
                size = write(sockfd, g_pSt_BurnUid_Req, sizeof(StBurnUidReq));
                if(size >= sizeof(StBurnUidReq))
                {
                    //从服务器获取返回值,先是协议头
                    ret = read(sockfd, &header_info, sizeof(header_info));
                    if ((ret >= sizeof(header_info)) &&
                        (BurnUid_Check_HeadInfo(&header_info, COMMAND_TYPES_AUTO_BURN_UID_RESP,
                                                sizeof(StBurnUidResp)) == 0))
                    {
                        StBurnUidResp resp_info;
                        memset(&resp_info, 0, sizeof(resp_info));

                        //读取服务器返回的UID、MAC地址
                        ret = read(sockfd, &resp_info, sizeof(resp_info));
                        if((ret >= sizeof(resp_info)))
                        {
                            PRT_INFO(DEF_TAG, "result:%d, uid:%s, DeviceSecret:%s, mac:%s,db:%d\n", resp_info.result,
                                     resp_info.device_id, resp_info.DeviceSecret, resp_info.encrypt_mac,
                                     resp_info.wifi__expert_signal_db);

                            if((resp_info.result == 0) || (resp_info.result == 3))
                            {
                                //save uuid and key
                                Ext_InSdkSetInfo_UUID(resp_info.device_id);
                                Ext_InSdkSetInfo_Authkey(resp_info.DeviceSecret);

                                if ((ret = BurnUid_Check_BurnStatus(&sockfd, &header_info, &resp_info)) < 0)
                                {
                                    PRT_ERR(DEF_TAG,"Check Burn Status failed !!\n");
                                }
                                else
                                {
                                    PRT_INFO(DEF_TAG,"Burn UID OK ~~~~~~~~!\n");
                                    system("touch /mnt/config/burn_uuid_ok");
                                    system("link_led_status.sh &");
                                    close(sockfd);
                                    return 0;
                                }
                            }
                        }
                    }
                }
            }
            close(sockfd);
        }
        sleep(1);
    }

    return 0;
}

int BurnUid_ReqResult(void)
{
    int ret;
    char result[512];
    char wifi_signal[48];
    char pid[DEF_COM_PID_LEN];
    char version[DEF_COM_VERSION_LEN];
    char wifi_rssi[DEF_COM_WIFI_RSSI_LEN];

    if (g_pSt_BurnUid_Req == NULL)
    {
        g_pSt_BurnUid_Req = malloc(sizeof(StBurnUidReq));
    }

    memset(pid,0,sizeof(pid));
    memset(result,0,sizeof(result));
    memset(wifi_rssi,0,sizeof(wifi_rssi));
    memset(wifi_signal,0,sizeof(wifi_signal));
    memset(version,0,sizeof(version));
    memset(g_pSt_BurnUid_Req, 0 , sizeof(StBurnUidReq));

    Ext_InSdkGetInfo_SocVer(version);
    Ext_InSdkGetInfo_WiFiRssi(wifi_rssi);
    sprintf (wifi_signal, "ty_burn_uuid:%s", wifi_rssi);
    sprintf (result,DEF_BURN_UID_STR_RET,DEF_BURN_UID_AP_NAME,version, wifi_signal);
    PRT_INFO(DEF_TAG,"%s\n",result);

    ret = Ext_InSdkGetInfo_Pid(pid);
    if(ret != DEF_COM_SUCCESS)
    {
        PRT_ERR(DEF_TAG,"get pid failed\n");
    }

    if (g_pSt_BurnUid_Req != NULL)
    {
        Ext_InSdkGetInfo_HardwareMac(g_pSt_BurnUid_Req->wireless_mac,MAC_SRC);
        strcpy(g_pSt_BurnUid_Req->system_version, version);
        strcpy(g_pSt_BurnUid_Req->mcu_version,"1.0");
        strcpy(g_pSt_BurnUid_Req->device_product_type, pid);
        strcpy(g_pSt_BurnUid_Req->test_result, result);
    }

    return 0;
}

int main(void)
{
    int ret;

    ret = BurnUid_ReqResult();
    if (ret != 0)
    {
        PRT_ERR(DEF_TAG,"set usr uid error !!\n");
    }

    /* 保证烧号没问题 */
    system("cp /usr/ipcam/bak/iot_config.ini /mnt/config/");
    BurnUid_From_Server();

    while(DEF_COM_TRUE)
    {
        PRT_DBG(DEF_TAG,">>>>>>>>>>>>>>>>>wait for reboot\n");
        sleep(1);
    }

    return 0;
}
